package main

import (
    "context"
    "fmt"
    "os"
    "os/signal"
    "syscall"
    "time"

    corev1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/watch"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
)

func main() {
    // 1. 加载 kubeconfig
    kubeconfig := os.Getenv("KUBECONFIG")
    if kubeconfig == "" {
        kubeconfig = clientcmd.RecommendedHomeFile // 默认 ~/.kube/config
    }

    config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
    if err != nil {
        panic(fmt.Errorf("failed to build config: %v", err))
    }

    // 2. 创建 Kubernetes 客户端
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(fmt.Errorf("failed to create client: %v", err))
    }

    // 3. 首次全量 List 操作
    pods, err := clientset.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        panic(fmt.Errorf("initial list failed: %v", err))
    }
    fmt.Printf("Initial List: Found %d pods\n", len(pods.Items))

    // 4. 初始化 Watch 参数
    watchOptions := metav1.ListOptions{
        ResourceVersion: pods.ResourceVersion, // 关键：从 List 结果版本开始监听增量事件
        AllowWatchBookmarks: true,              // 启用书签事件减少重连开销[6](@ref)
        TimeoutSeconds:      int64Ptr(300),     // 长连接超时时间
    }

    // 5. 启动 Watch 循环（带重试机制）
    for {
        watcher, err := clientset.CoreV1().Pods("default").Watch(context.TODO(), watchOptions)
        if err != nil {
            fmt.Printf("Watch connection error: %v, retrying...\n", err)
            time.Sleep(5 * time.Second)
            continue
        }

        // 6. 处理信号和事件流
        stopCh := make(chan os.Signal, 1)
        signal.Notify(stopCh, syscall.SIGINT, syscall.SIGTERM)

        eventCh := watcher.ResultChan()
    eventLoop:
        for {
            select {
            case event, ok := <-eventCh:
                if !ok { // 通道关闭时触发重连
                    fmt.Println("Watch channel closed, reconnecting...")
                    break eventLoop
                }
                handleEvent(event)
            case <-stopCh:
                watcher.Stop()
                fmt.Println("\nExiting...")
                return
            }
        }
    }
}

func handleEvent(event watch.Event) {
    pod, ok := event.Object.(*corev1.Pod)
    if !ok {
        fmt.Printf("[ERROR] Unexpected object type: %T\n", event.Object)
        return
    }

    switch event.Type {
    case watch.Added:
        fmt.Printf("[ADD] Pod: %s (Phase: %s)\n", pod.Name, pod.Status.Phase)
    case watch.Modified:
        fmt.Printf("[MOD] Pod: %s (Phase: %s)\n", pod.Name, pod.Status.Phase)
    case watch.Deleted:
        fmt.Printf("[DEL] Pod: %s\n", pod.Name)
    case watch.Bookmark:
        fmt.Printf("[BOOKMARK] RV: %s\n", pod.ResourceVersion)
    case watch.Error:
        fmt.Printf("[ERROR] %v\n", event.Object)
    }
}

func int64Ptr(i int64) *int64 { return &i }
